package com.spring;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/*
容器类
 */
public class ZzAplicationContext {

    private Class config;
    //单例池
    public static ConcurrentHashMap<String,Object> singletonMap=new ConcurrentHashMap<>();
    //bean的定义池
    public static ConcurrentHashMap<String,BeanDefination> beandefinationMaps=new ConcurrentHashMap<>();

    private List<BeanPostProcessor> beanPostProcessorslist=new LinkedList<>();

    public ZzAplicationContext(Class config) throws Exception {
        this.config=config;

        //解析配置类
        //ComponentScan注解------》扫描路径----》扫描----->形成BeanDefination--------》放进beandefinationMaps
        scan(config);
        for(Map.Entry<String, BeanDefination> entry :beandefinationMaps.entrySet()){
            String beanName=entry.getKey();
            BeanDefination beanDefination=entry.getValue();
            if(beanDefination.getScope().equals("singleton")){
                Object bean=createBean(beanName,beanDefination);
                singletonMap.put(beanName,bean);
            }
        }

    }

    Object createBean(String beanName,BeanDefination beanDefination) throws Exception {
        Class clazz= (Class) beanDefination.getClazz();
        Object instance=clazz.getDeclaredConstructor().newInstance();

        //依赖注入
        for (Field declaredField : clazz.getDeclaredFields()) {
            //判断属性上面有没有autowired注解
            if(declaredField.isAnnotationPresent(Autowired.class)){
                //进行属性的赋值
                Object bean=getBean(declaredField.getName());
                declaredField.setAccessible(true);
                declaredField.set(instance,bean);
            }
        }
        //判断是否实现了BeanNameAware接口    aware回调
        if(instance instanceof BeanNameAware){
            ((BeanNameAware) instance).setBeanName(beanName);
        }

        //BeanPostProcessor前置方法
        for (BeanPostProcessor beanPostProcessor:beanPostProcessorslist){
            instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
        }

        //初始化
        if(instance instanceof InitializingBean){
            ((InitializingBean) instance).afterPropertiesSet();
        }


        //BeanPostProcessor后置方法
        for (BeanPostProcessor beanPostProcessor:beanPostProcessorslist){
            instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
        }
        return instance;
    }

    private void scan(Class config) {
        ComponentScan configDeclaredAnnotation = (ComponentScan) config.getDeclaredAnnotation(ComponentScan.class);

        //获得值
        String path=configDeclaredAnnotation.value();

        System.out.println("扫描路径："+path);

        //进行扫描
        //使用类加载器进行加载
        ClassLoader classLoader=ZzAplicationContext.class.getClassLoader();
        //加载路径下的文件
        //使用app型加载器，因为path为相对路径，app型加载器加载的是classpath下的文件
        //获得目录
        URL resource= classLoader.getResource("com/zz/service");

        File file=new File(resource.getFile());

        if(file.isDirectory()){

            File[] files=file.listFiles();
            for (File file1 : files) {

                String filename=file1.getAbsolutePath();

                if(filename.endsWith(".class")){
                    String className=filename.substring(filename.indexOf("com"),filename.indexOf(".class"));
                    className=className.replace("\\",".");

                    try{
                        Class<?> clazz=classLoader.loadClass(className);

                        //判断当前类是否是bean
                        if(clazz.isAnnotationPresent(Component.class)) {

                            //判断是否实现了BeanPostProcessor接口
                            if(BeanPostProcessor.class.isAssignableFrom(clazz)){
                                BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
                                beanPostProcessorslist.add(beanPostProcessor);
                            }
                            //获取bean的名字
                            Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
                            String beanName = componentAnnotation.value();

                            BeanDefination beanDefination=new BeanDefination();
                            //设置类属性
                            beanDefination.setClazz(clazz);
                            if(clazz.isAnnotationPresent(Scope.class)){
                               Scope scopeAnnotation=clazz.getDeclaredAnnotation(Scope.class);
                               String scopeName=scopeAnnotation.value();
                               beanDefination.setScope(scopeName);
                            }else {
                                //默认为单例bean
                                beanDefination.setScope("singleton");
                            }


                            beandefinationMaps.put(beanName,beanDefination);
                        }



                    }catch (Exception e){
                        e.printStackTrace();
                    }

                }

            }
        }
    }

    public Object getBean(String beanName) throws Exception {

        if (beandefinationMaps.containsKey(beanName)) {
            BeanDefination beanDefination = beandefinationMaps.get(beanName);
            if (beanDefination.getScope().equals("singleton"))//单例
            {
                Object o = singletonMap.get(beanName);
                return o;
            } else {
                //原型
                Object bean = createBean(beanName, beanDefination);
                return bean;
            }
        } else {
            System.out.println("不存在");
            //不存在对应的bean
            throw new NullPointerException();
        }

    }



}
